package tech.horgee.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import tech.horgee.common.MyCode;
import tech.horgee.dto.PwdDTO;
import tech.horgee.entity.Dept;
import tech.horgee.entity.Post;
import tech.horgee.entity.User;
import tech.horgee.entity.UserRole;
import tech.horgee.enums.UserStatusEnum;
import tech.horgee.mapper.*;
import tech.horgee.utils.AssertUtil;
import tech.horgee.utils.AuthUtils;
import tech.horgee.utils.RsaUtil;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static tech.horgee.common.MyConstants.*;

/**
 * 用户信息 服务类
 *
 * @author haojun
 * @since 2022-06-12
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class UserService {
    private final UserMapper mapper;
    private final UserRoleMapper userRoleMapper;
    private final RoleMapper roleMapper;
    private final PostMapper postMapper;
    private final DeptMapper deptMapper;

    /**
     * 分页查询列表
     *
     * @param page   分页对象
     * @param entity 查询实体
     * @return 所有数据
     */
    public Page<User> page(Page<User> page, User entity) {
        Page<User> userPage = mapper.selectPage(page, entity.wrapper());
        userPage.setRecords(fillDPL(userPage.getRecords()));
        return userPage;
    }

    /**
     * 不分页查询列表
     *
     * @param entity 实体对象
     * @return 查询结果
     */
    public List<User> list(User entity) {
        LambdaQueryWrapper<User> wrapper = entity.wrapper()
                .select(User::getUserId, User::getNickname,
                        User::getEmail, User::getPhone, User::getAvatar);
        return mapper.selectList(wrapper);
    }

    /**
     * 填充部门/岗位/直属上级
     *
     * @param list 数据集
     * @return 处理后的数据集
     */
    private List<User> fillDPL(List<User> list) {
        if (CollectionUtils.isEmpty(list)) {
            return Collections.emptyList();
        }
        Set<Long> postIds = new HashSet<>();
        Set<Long> deptIds = new HashSet<>();
        Set<Long> leaderIds = new HashSet<>();
        list.forEach(user -> {
            postIds.add(user.getPostId());
            deptIds.add(user.getDeptId());
            leaderIds.add(user.getLeaderId());
        });
        Map<Long, String> leaderMap = mapper.selectBatchIds(leaderIds).stream().collect(Collectors.toMap(User::getUserId, User::getNickname));
        Map<Long, String> postMap = postMapper.selectBatchIds(postIds).stream().collect(Collectors.toMap(Post::getPostId, Post::getPostName));
        Map<Long, String> deptMap = deptMapper.selectBatchIds(deptIds).stream().collect(Collectors.toMap(Dept::getDeptId, Dept::getDeptName));
        return list.stream().peek(user -> {
            user.setLeader(leaderMap.get(user.getLeaderId()));
            user.setDept(deptMap.get(user.getDeptId()));
            user.setPost(postMap.get(user.getPostId()));
        }).toList();
    }

    /**
     * 通过主键查询单条数据
     *
     * @param id 主键
     * @return 单条数据
     */
    public User getById(Long id) {
        User user = mapper.selectById(id);
        if (Objects.nonNull(user)) {
            if (Objects.equals(id, SUPER_ADMIN_ID)) {
                user.setPermissions(Collections.singleton(SUPER_ADMIN_PERM));
            } else {
                user.setPermissions(roleMapper.listPermKey(id));
            }
            if (user.getLeaderId() > 0) {
                User leader = mapper.selectById(user.getLeaderId());
                user.setLeader(leader.getNickname());
            }
            if (user.getPostId() > 0) {
                Post post = postMapper.selectById(user.getPostId());
                user.setPost(post.getPostName());
            }
            if (user.getDeptId() > 0) {
                Dept dept = deptMapper.selectById(user.getDeptId());
                user.setDept(dept.getDeptName());
            }
        }
        AuthUtils.setUser(user);
        return user;
    }

    /**
     * 新增单条数据
     *
     * @param entity 实体对象
     */
    @Transactional(rollbackFor = Exception.class)
    public void save(User entity) {
        if (!StringUtils.hasText(entity.getNickname())) {
            entity.setNickname("用户" + RandomUtil.randomString(6));
        }
        if (!StringUtils.hasText(entity.getPassword())) {
            entity.setPassword(DEFAULT_PASSWORD);
        }
        mapper.insert(entity);
        insertUserRole(entity);
    }

    /**
     * 修改单条数据
     *
     * @param entity 实体对象
     */
    @Transactional(rollbackFor = Exception.class)
    public void update(User entity) {
        if (Objects.equals(entity.getUserId(), SUPER_ADMIN_ID)) {
            throw MyCode.ACCESS_DENIED.toException("超管账号不可编辑");
        }
        if (CollUtil.isNotEmpty(entity.getRoleIds())) {
            userRoleMapper.delete(new LambdaQueryWrapper<UserRole>().eq(UserRole::getUserId, entity.getUserId()));
            insertUserRole(entity);
        }
        if (entity.getStatus() == UserStatusEnum.LEAVE) {
            entity.setLeaveTime(LocalDateTime.now());
        } else {
            entity.setLeaveTime(null);
        }
        AssertUtil.onlyOne(mapper.updateById(entity));
    }

    /**
     * 批量删除数据
     *
     * @param ids 主键集合
     */
    @Transactional(rollbackFor = Exception.class)
    public void deleteByIds(Set<Long> ids) {
        if (ids.contains(SUPER_ADMIN_ID)) throw MyCode.ACCESS_DENIED.toException("超管账号不可删除");
        userRoleMapper.delete(new LambdaQueryWrapper<UserRole>().in(UserRole::getUserId, ids));
        AssertUtil.updated(mapper.deleteBatchIds(ids));
    }

    /**
     * 新增角色用户信息
     *
     * @param entity 用户对象
     */
    public void insertUserRole(User entity) {
        // 新增用户与角色管理
        if (CollUtil.isNotEmpty(entity.getRoleIds())) {
            List<UserRole> list = new ArrayList<>();
            for (Long roleId : entity.getRoleIds()) {
                UserRole rm = new UserRole();
                rm.setRoleId(roleId);
                rm.setUserId(entity.getUserId());
                list.add(rm);
            }
            if (!list.isEmpty()) userRoleMapper.batchUserRole(list);
        }
    }

    /**
     * 重置密码
     *
     * @param userId 用户ID
     */
    public void resetPassword(Long userId) {
        if (Objects.equals(userId, SUPER_ADMIN_ID)) throw MyCode.ACCESS_DENIED.toException("超管账号不可编辑");
        boolean exists = mapper.exists(new LambdaQueryWrapper<User>().eq(User::getUserId, userId));
        if (!exists) throw MyCode.UNKNOWN_ACCOUNT.toException();
        User user = new User();
        user.setUserId(userId);
        user.setPassword(DEFAULT_PASSWORD);
        mapper.updateById(user);
    }

    /**
     * 修改密码
     */
    public void changePwd(Long userId, PwdDTO dto) {
        User user = mapper.selectById(userId);
        if (Objects.isNull(user)) throw MyCode.UNKNOWN_ACCOUNT.toException();
        if (!RsaUtil.decrypt(user.getPassword()).equals(dto.getPasswordOld())) {
            throw MyCode.DATA_VERIFY_ERROR.toException("旧密码错误");
        }
        User info = new User();
        info.setUserId(userId);
        info.setPassword(dto.getPasswordNew());
        mapper.updateById(info);
    }

    /**
     * 修改头像
     */
    public void changeAvatar(Long userId, String avatar) {
        User user = mapper.selectById(userId);
        if (Objects.isNull(user)) throw MyCode.UNKNOWN_ACCOUNT.toException();
        User info = new User();
        info.setUserId(userId);
        info.setAvatar(avatar);
        mapper.updateById(info);
    }

    /**
     * 角色勾选项
     *
     * @param userId 用户ID
     * @return 角色IDs
     */
    public Set<Long> selectRoleIdsByUserId(Long userId) {
        return userRoleMapper.selectRoleIdsByUserId(userId);
    }


    /**
     * 选择用户选项模糊查询
     *
     * @param keyword 条件
     */
    public List<User> selectUser(String keyword) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(User::getUserId, User::getNickname)
                .like(User::getNickname, keyword)
                .or().like(User::getUserId, keyword)
                .last("limit 30");
        return mapper.selectList(wrapper);
    }
}
